/*
 * 版权所有 (c) 2025, Amor. 保留所有权利。
 * 基于MIT许可证条款分发。
 *
 * 作者：
 *		Amor
 */

#include <OS.h>
#include <boot/platform.h>
#include <boot/stdio.h>
#include <boot/kernel_args.h>
#include <boot/stage2.h>
#include <arch/cpu.h>
#include <arch_kernel.h>
#include <arch_system_info.h>
#include <string.h>

#define TRACE_CPU
#ifdef TRACE_CPU
#define TRACE(x) dprintf x
#else
#define TRACE(x) ;
#endif

// 使用cpucfg指令检测LoongArch CPU特性
static uint32_t
read_cpucfg(uint32_t reg)
{
    uint32_t val;
    asm volatile(
        "cpucfg %0, %1\n\t"
        : "=r"(val)
        : "r"(reg));
    return val;
}

// 初始化TLB（转译后备缓冲器）
static void
tlb_init(void)
{
    // 清除TLB条目
    asm volatile(
        "csrwr $zero, 0x19\n\t" // LOONGARCH_CSR_TLBIDX: 设置TLB索引为0
        "csrwr $zero, 0x1a\n\t" // LOONGARCH_CSR_TLBEHI: 清除TLB条目高位
        "csrwr $zero, 0x1b\n\t" // LOONGARCH_CSR_TLBELO0: 清除TLB条目低位0
        "csrwr $zero, 0x1c\n\t" // LOONGARCH_CSR_TLBELO1: 清除TLB条目低位1
        "tlbwr\n\t"             // 写入TLB
    );
}

// 设置异常向量表
static void
setup_exception_vectors(void)
{
    // 设置异常向量基地址（临时地址，后续会更新）
    asm volatile(
        "li.d $t0, 0x9000000000000000\n\t" // 内核虚拟地址空间基址
        "csrwr $t0, 0x1\n\t"               // LOONGARCH_CSR_EBASE: 异常入口基地址
    );

    // 设置向量大小并启用向量中断
    asm volatile(
        "li.d $t0, 0x3f\n\t"  // 向量间隔：0x3f = 64字节 (2^6 - 1)
        "csrwr $t0, 0xc2\n\t" // LOONGARCH_CSR_TLBRENTRY: 设置向量间隔
    );
}

// 初始化早期调试控制台
static void
init_early_console(void)
{
    // 3A6000 UART基地址（占位符 - 需替换为实际地址）
    // 后续将在平台特定代码中正确初始化
    // 目前仅建立基本结构
}

/*! 检测LoongArch CPU特性
 */
static status_t
check_cpu_features()
{
    // 使用cpucfg指令读取CPU配置
    uint32_t cpucfg1 = read_cpucfg(1); // 基础CPU信息
    uint32_t cpucfg2 = read_cpucfg(2); // CPU 特性

    TRACE(("LoongArch CPU: CPUCFG1=0x%08x, CPUCFG2=0x%08x\n", cpucfg1, cpucfg2));

    // 检查是否为LoongArch CPU
    if ((cpucfg1 & 0xffff0000) != 0x14000000)
    {
        panic("Not a LoongArch CPU!\n");
        return B_ERROR;
    }

    // 提取CPU信息
    uint32_t arch_version = (cpucfg1 >> 16) & 0xffff; // 架构版本
    uint32_t core_id = cpucfg1 & 0xffff;              // 核心ID

    TRACE(("LoongArch CPU: Architecture version: %d, Core ID: %d\n",
           arch_version, core_id));

    return B_OK;
}

extern "C" status_t
boot_arch_cpu_init(void)
{
    status_t err = check_cpu_features();
    if (err != B_OK)
    {
        panic("Failed to initialize LoongArch CPU!\n");
        return err;
    }

    // Initialize TLB
    tlb_init();

    // Setup exception vectors
    setup_exception_vectors();

    // Initialize early console
    init_early_console();

    return B_OK;
}

extern "C" void
arch_ucode_load(BootVolume &volume)
{
    // Not implemented for LoongArch64 currently
}

extern "C" bigtime_t
system_time()
{
    // Read the stable counter (similar to ARM's cntpct_el0)
    uint64_t ticks;
    asm volatile("rdtime.d %0, $zero" : "=r"(ticks));

    // TODO: Implement proper frequency conversion
    // For now, we just return the raw ticks
    return ticks;
}

extern "C" void
spin(bigtime_t microseconds)
{
    bigtime_t time = system_time();
    while ((system_time() - time) < microseconds)
        asm volatile("nop");
}